//
//  MapProView.swift
//  JiaoZiTaxi
//
//  Created by Hu Gang on 2022/10/8.
//

import Combine
import MapKit
import SwiftUI

struct MapViewWrapper: UIViewRepresentable {
    typealias UIViewType = MKMapView
    @Binding var route: MKPolyline?
    static let reuseId = "car"
    
    @Binding var centerCoordinate: CLLocationCoordinate2D
    @Binding var selectedPlace: MKPointAnnotation?
    @Binding var showingPlaceDetails: Bool
    @Binding var currentLocation: CLLocationCoordinate2D
    
    @Binding var startCoordinate: CLLocationCoordinate2D
    @Binding var endCoordinate: CLLocationCoordinate2D
    
    @State var isFirst: Bool = true
    
    let mapView: MKMapView
    
    @ObservedObject var config = MapConfig.shared
    @ObservedObject var order = CarOrder.shared
    
    @StateObject private var pathManager = MapPathManager()
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> MKMapView {
        print("makeUIView...")
        let loc = currentLocation.shift()
        let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: loc.latitude, longitude: loc.longitude), span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005))
        
        mapView.region = region
        mapView.delegate = context.coordinator
        mapView.userTrackingMode = .follow
        mapView.showsScale = true
        mapView.showsUserLocation = true
        mapView.register(CarAnnotationView.self, forAnnotationViewWithReuseIdentifier: MapViewWrapper.reuseId)
        addAnnotation(to: mapView)
        addStartPosAnnotation(uiView: mapView) // 出发位置
        addEndPosAnnotation(uiView: mapView) // 终点位置
        
        mapView.setCenter(loc, animated: true)
        
        return mapView
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        print("[Map] updateUIView...\(config.annotationItems.count)")
        
        // 1 自己位置  2 起始点 3 终点
        // (config.annotationItems.count != uiView.annotations.count - 3) ||
        if config.changed || (uiView.annotations.count <= 3 && order.endPos != nil) || ( uiView.annotations.count <= 2 && order.endPos  == nil )  {
            //uiView.removeAnnotations(uiView.annotations)
            
            for item in uiView.annotations {
                print("[Map] remove car annotation \(String(describing: item.title!))")
                if item is CarAnnotation {
                    print("[Map] removed car annotation \(String(describing: item.title!))")
                    uiView.removeAnnotation(item)
                }
            }
            
            addAnnotation(to: uiView)
            
            if config.annotationItems.count == 1 {
                addRoute(to: uiView)
            }
            
            if config.changed {
                config.changed.toggle()
            }
            
        } else {
            moveAnnotation(to: uiView)
        }
        
        if config.startOrEndChanged {
            print("[Map] start or end point changed ... \(String(describing: CarOrder.shared.startPos))  \(String(describing: CarOrder.shared.endPos))")
            var count = 0
            for item in uiView.annotations {
                if item.title == "Start" || item.title == "End" {
                    print("[Map] point \(String(describing: item.title)) removed.")
                    uiView.removeAnnotation(item)
                    count += 1
                    if count == 2 {
                        break
                    }
                }
            }
            print("[Map] before add start or end annotation:\(mapView.annotations.count)")
            print("add start pos annotation 添加到 \(String(describing: CarOrder.shared.startPos))  \(String(describing: CarOrder.shared.endPos))")
            
            addStartPosAnnotation(uiView: uiView)
            addEndPosAnnotation(uiView: uiView)
            if CarOrder.shared.startPos != nil && CarOrder.shared.endPos != nil {
                pathManager.loadPath(startPos: CarOrder.shared.startPos!, endPos: CarOrder.shared.endPos!) { pathArr in
                    var resultArr = pathArr
                    // 把定位的起点和终点加入数组
                    resultArr.insert(CarOrder.shared.startPos!, at: 0)
                    resultArr.append(CarOrder.shared.endPos!)
                    DispatchQueue.main.async {
                        drawPathCoordinate(to: uiView, pathArr: resultArr)
                    }
                    
                }
            }
            if CarOrder.shared.startPos == nil || CarOrder.shared.endPos == nil {
                uiView.removeOverlays(uiView.overlays)
            }
//            drawPath(to: uiView, isShow: CarOrder.shared.endPos != nil)
            config.startOrEndChanged = false
        }else {
            print("add start pos annotation 没添加 \(String(describing: CarOrder.shared.startPos))  \(String(describing: CarOrder.shared.endPos))")
        }
    }
    
    func makeUserLocationCenter() {
        mapView.setCenter(centerCoordinate, animated: true)
    }
    
    func addStartPosAnnotation(uiView: MKMapView) {
        if let pos = CarOrder.shared.startPos {
            print("[Map] add start pos annotation:\(pos.longitude) \(pos.latitude)")
            let startPin = MKPointAnnotation()
            startPin.coordinate = pos
            startPin.title = "Start"
            uiView.addAnnotation(startPin)
            print("[Map] add start pos annotation over :\(mapView.annotations.count)")
        } else {
            print("[Map] add start pos annotation: 【default】 \(startCoordinate.longitude) \(startCoordinate.latitude)")
            let startPin = MKPointAnnotation()
            startPin.coordinate = startCoordinate
            startPin.title = "Start"
            uiView.addAnnotation(startPin)
            print("[Map] add start pos annotation  【default】 over :\(mapView.annotations.count)")
        }
    }
    
    func addEndPosAnnotation(uiView: MKMapView) {
        if let pos = CarOrder.shared.endPos {
            print("[Map] add end pos annotation:\(pos.longitude) \(pos.latitude)")
            let endPin = MKPointAnnotation()
            endPin.coordinate = pos
            endPin.title = "End"
            uiView.addAnnotation(endPin)
            print("[Map] add end pos annotation over :\(mapView.annotations.count)")
        }
        // else {
        //         print("[Map] add end pos annotation: 【default】 \(endCoordinate.longitude) \(endCoordinate.latitude)")
        //         let endPin = MKPointAnnotation()
        //         endPin.coordinate = endCoordinate
        //         endPin.title = "End"
        //         uiView.addAnnotation(endPin)
        //         print("[Map] end start pos annotation  【default】 over :\(mapView.annotations.count)")
        //      }
    }
    
    func addAnnotation(to mapView: MKMapView) {
        // print("addAnnotation.")
        
        for item in config.annotationItems {
            var carImage = "yellowcar"
            if item.car.speed > 0 {
                carImage = "redcar"
            }
            // 设置地图上车
            let anno = CarAnnotation(
                coordinate: item.coordinate,
                type: "car",
                image: UIImage(named: carImage)!
                    .resizeImage(targetSize: CGSize(width: 36, height: 36))!
                    .rotated(byDegrees: item.car.direction)!,
                
                carNo: item.car.carNo
            )
            // print("anno:\(anno)")
            mapView.addAnnotation(anno)
        }
    }
    
    func moveAnnotation(to mapView: MKMapView) {
        for item in config.annotationItems {
            for itemView in mapView.annotations {
                if let anno = itemView as? CarAnnotation {
                    if anno.title == item.car.carNo {
                        anno.coordinate = item.coordinate
                        break
                    }
                }
            }
        }
    }
    
    func addRoute(to view: MKMapView) {
        if !view.overlays.isEmpty {
            var deletOverlays: [MKOverlay] = []
            for overlay in view.overlays {
                if overlay.title != "path" {
                    deletOverlays.append(overlay)
                }
            }
            view.removeOverlays(deletOverlays)
        }
        
        guard let route = route else { return }
        
        if WebSocketService.shared.orderState != .none {
//            if isFirst { // 第一次拉进距离
//                let mapRect = route.boundingMapRect
//                view.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), animated: true)
//                self.isFirst = false
//            }
            view.addOverlay(route)
        }
    }
    
    func drawPath(to view: MKMapView, isShow: Bool) {
        // 1.创建包含位置坐标的地标对象
        let startPlacemark = MKPlacemark(coordinate: ViewModel.shared.startLocation)
        let endPlacemark = MKPlacemark(coordinate: ViewModel.shared.endLocation)
        // 2.MKMapitems用于路线的绘制。 此类封装有关地图上特定点的信息
        let startMapItem = MKMapItem(placemark: startPlacemark)
        let endMapItem = MKMapItem(placemark: endPlacemark)
        // 3.MKDirectionsRequest类用于计算路线。折线
        let directionRequest = MKDirections.Request()
        directionRequest.source = startMapItem
        directionRequest.destination = endMapItem
        directionRequest.transportType = .automobile
        // 删除原来的线
        if !isShow {
            view.removeOverlays(view.overlays)
        }
        // Calculate the direction
        let directions = MKDirections(request: directionRequest)
        // 8.将使用折线作为地图顶部的叠加视图绘制路线。区域设置为两个位置都可见
        directions.calculate { (response, error) -> Void in
            guard let response = response else {
                if let error = error {
                    print("Error: \(error)")
                }
                return
            }
            let route = response.routes[0]
            route.polyline.title = "one"
            view.removeOverlays(view.overlays)
            view.addOverlay((route.polyline), level: MKOverlayLevel.aboveRoads)
            if isShow {
                let rect = route.polyline.boundingMapRect
                view.setRegion(MKCoordinateRegion(rect), animated: true)
            }
        }
    }
    
    // 根据经纬度绘制路线
    func drawPathCoordinate(to view: MKMapView, pathArr: [CLLocationCoordinate2D]) {
        var deletOverlays: [MKOverlay] = []
        for overlay in view.overlays {
            if overlay.title == "path" {
                deletOverlays.append(overlay)
            }
        }
        view.removeOverlays(deletOverlays)
        // 创建一个polyline
        let polyline = MKPolyline(coordinates: pathArr, count: pathArr.count)
        polyline.title = "path"
        view.addOverlay(polyline)
        // 设置地图显示范围
//        view.showAnnotations(view.annotations, animated: true)
    }
    
    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapViewWrapper
        var isFirst = true
        
        private var subscriptions: Set<AnyCancellable> = []
        
        init(_ parent: MapViewWrapper) {
            self.parent = parent
            super.init()
            NotificationCenter.default.publisher(for: .gotoCurrentLocation)
                .receive(on: DispatchQueue.main)
                .sink { [weak self] _ in
                    let lastUserLocation = ViewModel.shared.lastLocation
//                    self!.parent.mapView.region =  MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: lastUserLocation.latitude, longitude: lastUserLocation.longitude), span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005))
                    self!.parent.mapView.setCenter(lastUserLocation, animated: true)
                    
                }
                .store(in: &subscriptions)
        }
        
        func setLocation(to location: CLLocationCoordinate2D) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                // self.parent.mapViewState.center =  location
            }
        }
        
        func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
            print("change visible region...")
            // if !mapView.showsUserLocation {
            DispatchQueue.main.async {
                self.parent.centerCoordinate = mapView.centerCoordinate
                self.parent.config.followMode = false
            }
            // }
        }
        
        func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
            print("regionDidChangeAnimated...")
        }
        
        func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
            print("regionWillChangeAnimated.")
        }
        
        func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
            print("map update user location:\(userLocation.coordinate)")
            if ViewModel.shared.needReturnToUserLocation || parent.config.followMode {
                mapView.setCenter(userLocation.coordinate, animated: true)
                ViewModel.shared.needReturnToUserLocation.toggle()
            }
            
            CarOrder.shared.passengerPosition = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
            ViewModel.shared.lastLocation = userLocation.coordinate
            CarOrder.shared.startPos = ViewModel.shared.lastLocation
            print("地图拿到的位置 \(ViewModel.shared.lastLocation.longitude) \(ViewModel.shared.lastLocation.latitude)")
//            NotificationCenter.default.post(name: .location, object: nil, userInfo: ["location":CarOrder.shared.startPos ?? nil])
            MapConfig.shared.startOrEndChanged = true;
            if let carPos = CarOrder.shared.carPosition {
                parent.route = WebSocketService.shared.drawRout(first: ViewModel.shared.lastLocation, second: carPos)
                parent.addRoute(to: mapView)
            }
            
            print("drawRout map gps:\(userLocation.coordinate.longitude) \(userLocation.coordinate.latitude)")
        }
        
        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            print("[Map]-[mapView viewFor]  \(String(describing: annotation.title))")
            let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MapViewWrapper.reuseId, for: annotation) as! CarAnnotationView
            
            if let carAnnotation = annotation as? CarAnnotation {
                if carAnnotation.subtitle == "car" {
                    annotationView.image = carAnnotation.image
                    annotationView.carNo = carAnnotation.title!
                }
            } else {
                print("[Map]-[mapView viewFor] Not car \(String(describing: annotation.title))")
                annotationView.carNo = ""
                
                if annotation.title! == "Start" {
                    if let _ = CarOrder.shared.startPos {
                        print("[Map] show start point:\(annotation.coordinate)")
                        annotationView.image = UIImage(named: "startPoint")?.resizeImage(targetSize: CGSize(width: 40, height: 60))
                    } else {
                        print("[Map] show start point invisible:\(annotation.coordinate)")
                        annotationView.image = UIImage(named: "startPoint1")?.resizeImage(targetSize: CGSize(width: 40, height: 60))
                    }
                } else if annotation.title! == "End" {
                    if let _ = CarOrder.shared.endPos {
                        print("[Map] show end point :\(annotation.coordinate)")
                        annotationView.image = UIImage(named: "endPoint")?.resizeImage(targetSize: CGSize(width: 40, height: 60))
                    } else {
                        print("[Map] show end point invisible:\(annotation.coordinate)")
                        annotationView.image = UIImage(named: "endPoint1")?.resizeImage(targetSize: CGSize(width: 40, height: 60))
                    }
                } else {
                    annotationView.image = UIImage(named: "location-icon")?.resizeImage(targetSize: CGSize(width: 32, height: 32))
                }
            }
            
            print("[Map] \(String(describing: annotation.title!))")
            
            return annotationView
        }
        
        func customAnnotationView(in mapView: MKMapView, for annotation: MKAnnotation) -> CarAnnotationView {
            let identifier = "CustomAnnotationView_Car"
            
            if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? CarAnnotationView {
                annotationView.annotation = annotation
                return annotationView
            } else {
                let customAnnotationView = CarAnnotationView(annotation: annotation, reuseIdentifier: identifier)
                customAnnotationView.canShowCallout = true
                return customAnnotationView
            }
        }
        
        func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
          
//            if let carAnnotation = view.annotation as? CarAnnotation {
//                if carAnnotation.subtitle == "car" {
//                    
//                    let notice = Notification(name: .callSpecCar, object: nil, userInfo: ["car": carAnnotation.title as Any])
//                    NotificationCenter.default.post(notice)
//                }
//            }
        }
        
        // 渲染overlay的函数
        func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
            print("draw line.")
            var shouldCount = 4
            if parent.order.endPos == nil {
                shouldCount = 3
            }
            if mapView.annotations.count ==  shouldCount, WebSocketService.shared.orderState == .waiting {
                if let routePolyline = overlay as? MKPolyline {
                    if routePolyline.title != "path" { // 不是路径线
                        let renderer = MKPolylineRenderer(polyline: routePolyline)
                        renderer.strokeColor = UIColor.red.withAlphaComponent(0.6)
                        renderer.lineDashPattern = [2, 5]
                        renderer.lineWidth = 2
                        return renderer
                    }
                }
            }
            // 路线绘制
            if let routePolyline = overlay as? MKPolyline {
                if routePolyline.title == "path" { // 判断是路径线
                    let renderer = MKPolylineRenderer(polyline: routePolyline)
                    renderer.strokeColor = UIColor.red.withAlphaComponent(0.6)
                    renderer.lineWidth = 4
                    return renderer
                }
            }
            return MKOverlayRenderer()
        }
        
        func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
            guard let placemark = view.annotation as? MKPointAnnotation else { return }
            parent.selectedPlace = placemark
            parent.showingPlaceDetails = true
        }
    }
}

class CarAnnotation: NSObject, MKAnnotation {
    @objc dynamic var coordinate: CLLocationCoordinate2D
    let title: String?
    let subtitle: String?
    var image: UIImage?
    
    init(coordinate: CLLocationCoordinate2D, type: String, image: UIImage, carNo: String) {
        self.coordinate = coordinate
                self.title = carNo
//        self.title = ""
        self.subtitle = type
        self.image = image
    }
}

class MapPathManager: ObservableObject {
    
    @Published var pathArr: [CLLocationCoordinate2D] = []
    
    func loadPath(startPos: CLLocationCoordinate2D, endPos: CLLocationCoordinate2D, completion: @escaping ([CLLocationCoordinate2D]) -> Void) {
        let openId = ViewModel.shared.passenger.openId
        Api.getCarPath(openId: openId, startLat: "\(startPos.latitude)", startLon: "\(startPos.longitude)", endLat: "\(endPos.latitude)", endLon: "\(endPos.longitude)") { r in
            switch r {
            case .success(let success):
                print("\(success)")
                var firstObject = success.first
                
                if let data = firstObject {
                    NotificationCenter.default.post(name: .distancePrice, object: nil, userInfo: ["distancePrice":data])
                }
                
                self.pathArr = success.map({ coordinate in
                    return CLLocationCoordinate2D(latitude: coordinate.lat, longitude: coordinate.lng)
                })
                completion(self.pathArr)
            case .failure(let failure):
                print("\(failure)")
            }
        }
    }
    
}

